﻿using MaterialWinforms.Animations;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;

namespace MaterialWinforms.Controls
{
    public class MaterialFloatingActionButton : Button, IShadowedMaterialControl
    {
        private Timer timerMouse;
        private bool isShowOrHide = false;

        [Browsable(false)]
        public int Depth { get; set; }

        [Browsable(false)]
        public MaterialWinformsManager SkinManager { get { return MaterialWinformsManager.Instance; } }

        [Browsable(false)]
        public MouseState MouseState { get; set; }

        [Category("Appearance")]
        private Image _Icon;
        public Image Icon
        {
            get { return _Icon; }
            set
            {
                _Icon = value;
                this.Invalidate();
            }
        }

        [Category("Appearance")]
        private double _IconSize = 0.8;
        public double IconSize
        {
            get { return _IconSize; }
            set
            {
                // 判断值是否合法
                if (value <= 0 || value > 1)
                {
                    return;
                }
                _IconSize = value;

                // 重绘界面
                Invalidate();
            }
        }

        public int Elevation { get; set; }

        [Browsable(false)]
        public GraphicsPath ShadowBorder { get; set; }

        public override Color BackColor { get; set; } = Color.White;

        [Browsable(false)]
        [DefaultValue(typeof(int), "48")]
        public int Breite { get { return this.Width; } set { this.Width = value; } }

        [Browsable(false)]
        [DefaultValue(typeof(int), "48")]
        public int Hoehe { get { return this.Height; } set { this.Height = value; } }

        private string _toolTip = "";
        public string ToolTip
        {
            get
            {
                return _toolTip;
            }
            set
            {
                _toolTip = value;
                if (_toolTip != "")
                {
                    tooltipControl.SetToolTip(this, _toolTip);
                }
                else
                {
                    tooltipControl.RemoveAll();
                }
            }
        }

        private bool _isBordered = false;
        public bool IsBordered
        {
            get
            {
                return _isBordered;
            }
            set
            {
                _isBordered = value;
                Invalidate();
            }
        }

        private int currentAlpha;
        private int goalAlpha;

        private ToolTip tooltipControl;

        private readonly AnimationManager animationManager;
        private readonly AnimationManager hoverAnimationManager;

        public MaterialFloatingActionButton()
        {
            // 本体的属性
            Height = 48;
            Width = 48;
            Elevation = 2;
            Text = "";

            timerMouse = new Timer();
            timerMouse.Interval = 15;
            timerMouse.Tick += TimerMouse_Tick;

            // 提示窗口的属性
            tooltipControl = new ToolTip
            {
                InitialDelay = 500,
                ReshowDelay = 500,
                AutomaticDelay = 500,
                AutoPopDelay = 20000,
                ShowAlways = true
            };

            // 一些方法
            animationManager = new AnimationManager(false)
            {
                Increment = 0.03,
                AnimationType = AnimationType.EaseOut
            };
            hoverAnimationManager = new AnimationManager
            {
                Increment = 0.07,
                AnimationType = AnimationType.Linear
            };
            hoverAnimationManager.OnAnimationProgress += sender => Invalidate();
            animationManager.OnAnimationProgress += sender => Invalidate();
            SizeChanged += Redraw;
            LocationChanged += Redraw;
            ParentChanged += new System.EventHandler(onParentChanged);
            MouseEnter += MaterialCard_MouseEnter;
            MouseLeave += MaterialCard_MouseLeave;
        }

        private void TimerMouse_Tick(object sender, EventArgs e)
        {
            if (isShowOrHide)
            {
                if (currentAlpha < goalAlpha)
                {
                    currentAlpha += 10;
                    this.Invalidate();
                }
                else
                {
                    timerMouse.Stop();
                }
            }
            else
            {
                if (currentAlpha > goalAlpha)
                {
                    currentAlpha -= 10;
                    this.Invalidate();
                }
                else
                {
                    timerMouse.Stop();
                }
            }
        }

        void MaterialCard_MouseLeave(object sender, System.EventArgs e)
        {
            Elevation /= 2;
            Redraw(null, null);
        }

        void MaterialCard_MouseEnter(object sender, System.EventArgs e)
        {
            Elevation *= 2;
            Redraw(null, null);
        }

        private void Redraw(object sender, System.EventArgs e)
        {
            if (ShadowBorder != null)
            {
                ShadowBorder.Dispose();
            }
            ShadowBorder = new GraphicsPath();
            ShadowBorder = DrawHelper.CreateCircle(Location.X,
                                    Location.Y,
                                    ClientRectangle.Width / 2 - 1);
            if (Width != Height)
            {
                Width = Math.Min(Width, Height);
                Height = Math.Min(Width, Height);
            }

            Invalidate();
        }

        private void onParentChanged(object sender, System.EventArgs e)
        {
            if (Parent != null)
            {
                Parent.BackColorChanged += new System.EventHandler(Redraw);
                Parent.Invalidate();
            }
        }

        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            base.OnMouseUp(mevent);

            animationManager.StartNewAnimation(AnimationDirection.In, mevent.Location);
        }

        protected override void OnPaint(PaintEventArgs pevent)
        {
            var g = pevent.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.TextRenderingHint = TextRenderingHint.AntiAlias;

            Region = new Region(DrawHelper.CreateCircle(ClientRectangle.X,
                                    ClientRectangle.Y,
                                    ClientRectangle.Width / 2));
            g.Clear(this.BackColor);

            if (_Icon != null)
            {
                g.DrawImage(_Icon, Convert.ToInt32(Math.Round(ClientRectangle.Width * (1 - IconSize) / 2)), Convert.ToInt32(Math.Round(ClientRectangle.Height * (1 - IconSize) / 2)), Convert.ToInt32(Math.Round(ClientRectangle.Width * IconSize)), Convert.ToInt32(Math.Round(ClientRectangle.Height * IconSize)));
            }

            using (Brush b = new SolidBrush(Color.FromArgb((int)(hoverAnimationManager.GetProgress() * this.BackColor.A), this.BackColor.RemoveAlpha())))
            {
                g.FillEllipse(b, ClientRectangle);
                
                if (_isBordered)
                {
                    g.DrawEllipse(new Pen(Color.Black, 1), ClientRectangle);
                }
            }

            if (animationManager.IsAnimating())
            {
                for (int i = 0; i < animationManager.GetAnimationCount(); i++)
                {
                    var animationValue = animationManager.GetProgress(i);
                    var animationSource = animationManager.GetSource(i);
                    var rippleBrush = new SolidBrush(Color.FromArgb((int)(51 - (animationValue * 50)), Color.White));
                    var rippleSize = (int)(animationValue * Width * 2);
                    g.FillEllipse(rippleBrush, new Rectangle(animationSource.X - rippleSize / 2, animationSource.Y - rippleSize / 2, rippleSize, rippleSize));
                }
            }

            if (MouseState == MouseState.HOVER && !DesignMode)
            {
                if (currentAlpha == 0)
                {
                    isShowOrHide = true;
                    goalAlpha = 120;
                    timerMouse.Stop();
                    timerMouse.Start();
                }
                else
                {
                    g.FillEllipse(new SolidBrush(Color.FromArgb(currentAlpha, 255, 255, 255)), ClientRectangle);
                }
            }
            else
            {
                currentAlpha = 0;
            }
            //else if (MouseState == MouseState.OUT)
            //{
            //    if (currentAlpha == 120)
            //    {
            //        isShowOrHide = false;
            //        goalAlpha = 0;
            //        timerMouse.Stop();
            //        timerMouse.Start();
            //    }
            //    else if (currentAlpha != 0)
            //    {
            //        g.FillEllipse(new SolidBrush(Color.FromArgb(currentAlpha, 255, 255, 255)), ClientRectangle);
            //    }
            //}
        }

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            if (DesignMode) return;

            MouseState = MouseState.OUT;
            MouseEnter += (sender, args) =>
            {
                MouseState = MouseState.HOVER;
                Invalidate();
            };
            MouseLeave += (sender, args) =>
            {
                MouseState = MouseState.OUT;
                hoverAnimationManager.StartNewAnimation(AnimationDirection.Out);
                Invalidate();
            };
            MouseDown += (sender, args) =>
            {
                if (args.Button == MouseButtons.Left)
                {
                    MouseState = MouseState.DOWN;

                    animationManager.StartNewAnimation(AnimationDirection.In, args.Location);
                    Invalidate();
                }
            };
            MouseUp += (sender, args) =>
            {
                Invalidate();
            };
        }
    }
}

